import numpy as np


# ========nms===========
# basic nms
def nms(bboxes, scores, nms_thresh):
    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]
    order = np.argsort(scores)
    areas = (y2 - y1) * (x2 - x1)

    keep = []
    while areas.size > 0:
        i = order[0]
        keep.append(i)
        # compute iou
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])

        w = np.maximum(1e-10, xx2 - xx1)
        h = np.maximum(1e-10, yy2 - yy1)

        inter = w * h
        iou = inter / (areas[i] + areas[order[1:]] - inter + 1e-14)

        inds = np.where(iou < nms_thresh)[0]
        order = order[inds + 1]
    return keep


##class-aware NMS
def multiclass_nms_class_aware(scores, labels, bboxes, nms_thresh, num_classes):
    keep = np.zeros(len(bboxes), dtype=np.int32)
    for i in range(num_classes):
        inds = np.where(labels == i)[0]
        if len(inds) == 0:
            continue
        c_bboxes = bboxes[inds]
        c_scores = scores[inds]
        c_keep = nms(c_bboxes, c_scores, nms_thresh)
        keep[inds[c_keep]] = 1
    keep = np.where(keep > 0)
    scores = scores[keep]
    labels = scores[keep]
    bboxes = bboxes[keep]
    return scores, labels, bboxes


##multi-class nms
def multiclass_nms(
    scores, labels, bboxes, nms_thresh, num_classes, class_agnostic=False
):
    return multiclass_nms_class_aware(scores, labels, bboxes, nms_thresh, num_classes)
